#ifndef SIMDEFS_H_

#define SIMDEFS_H_

#include <list>
#include <vector>
#include <limits>
#include <cassert>
#include <cmath>
#include <stdio.h>


#include "pstdint.h"


//macros
#define NEW_VAR_OBJECT(ObjClass, obj, ParamList) ObjClass *obj; {obj = new ObjClass ParamList;};
#define NEW_VAR_OBJECT2(ObjClass, ObjClass2, obj, ParamList) ObjClass *obj; {obj = new ObjClass2 ParamList;};
#define NEW_OBJECT(ObjClass, obj, ParamList) {obj = new ObjClass ParamList;};
#define RELEASE_OBJ(p) {if(NULL!=p) p->release(); p=NULL;}

#define assert_or_ret(con) assert(con);\
	if (!(con)) return;
#define assert_or_retv(con,ret) assert(con);\
	if (!(con)) return ret;

//endof macros

//forward declaration
class Event;
class Node;
class ChordNode;
class ChordKeyInfo;
class ChordProtocol;

//end of forward declaration

//typedefs
typedef double sim_time_t;
typedef uint32_t node_id_t;
typedef uint32_t app_data_item_t;
typedef uint32_t sim_key_t; 

typedef std::list<Event*> TEventQueue;
typedef std::vector<Event*> TEventVector;
typedef std::vector<Node*> TNodeVector;
typedef std::vector<ChordNode*> TChordNodeVector;
typedef std::vector<node_id_t> TNodeIDVector; 
typedef std::vector<app_data_item_t> TAppDataVector; 
typedef std::list<ChordKeyInfo*> TChordKeyInfoList;
typedef std::list<ChordProtocol*> TChordProtocolList;

//end of typedefs

//constant variables
const node_id_t invalid_node_id = std::numeric_limits<uint32_t>::max();
const sim_time_t invalid_sim_time = -1.0;
const double epsilon = 0.00000000001;
//end of constant variables

//structures
//end of structures

/*Function objects*/
struct ReleaseObject {
	template<typename T>
		void operator()(T* ptr) const
		{
			RELEASE_OBJ( ptr );
		}
};

struct AcquireObject {
	template<typename T>
		void operator()(T* ptr) const
		{
			ptr->add_reference();
		}
};

/*Helper functons*/

namespace Helper{
sim_key_t round_sum( sim_key_t left, sim_key_t right );

	// [a,b]
	inline bool isBetweenEq(sim_key_t pos, sim_key_t firstpos, sim_key_t lastpos)
	{
		if(firstpos<lastpos)
		{
			// f  l 0
			// 0  f l
			return (pos>=firstpos)&&(pos<=lastpos);
		} else if(firstpos==lastpos){
			return (pos==firstpos);
		}else
		{
			// f 0 l
			return (pos>=firstpos)||(pos<=lastpos);
		}
		return false;
	}
	// (a,b]
	inline bool isBetweenGt(sim_key_t pos, sim_key_t firstpos, sim_key_t lastpos)
	{
		if(firstpos==lastpos) return false;
		return isBetweenEq(pos,firstpos+1,lastpos);
	}
	// [a,b)
	inline bool isBetweenLt(sim_key_t pos, sim_key_t firstpos, sim_key_t lastpos)
	{
		if(firstpos==lastpos) return false;
		if( round_sum(firstpos,1)==lastpos ) return (pos==firstpos);
		return isBetweenEq(pos,firstpos,lastpos-1);
	}
	// (a,b)
	inline bool isBetween(sim_key_t pos, sim_key_t firstpos, sim_key_t lastpos)
	{
		if(firstpos==lastpos) return false;
		if( round_sum(firstpos,1)==lastpos ) return false;
		return isBetweenEq(pos,firstpos+1,lastpos-1);
	}

	inline sim_key_t round_distance( sim_key_t firstpos, sim_key_t lastpos )
	{
		sim_key_t diff;
		sim_key_t max_key = std::numeric_limits<sim_key_t>::max();
		if ( lastpos > firstpos )
			diff = lastpos - firstpos;
		else {
			diff = max_key - firstpos + lastpos + 1;
		}
		return diff;
	}

	//This function ensures the type of two operands is sim_key_t thus
	//the result will overflow as we expect
	inline sim_key_t round_sum( sim_key_t left, sim_key_t right )
	{
		//assume long double is large enough
		//double max_value = std::numeric_limits<sim_key_t>::max();
		//double result = left + right;
		//if ( result > max_value ){
			//result = result - max_value - 1;
		//}

		return ( ((sim_key_t)left) + ((sim_key_t)right) );
	}

	//TODO: error number return
	inline double log( double x, double base ){
		assert( x>0 );
		assert( base>0 && base!=1 );
		return std::log( x ) / std::log( base );
	}
};


#endif /* SIMDEFS_H_ */

